package com.linshidream.intrachat.simplenio.packet.handler;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Created on 2025/8/1 12:41
 *
 * @author linshidream
 * @version 1.0.0
 * @description
 */

public class PacketWriter {

    private final SocketChannel channel;

    private final Selector selector;

    private Queue<ByteBuffer> writeQueue = new ConcurrentLinkedQueue<>();

    public PacketWriter(SocketChannel channel, Selector selector) {
        this.channel = channel;
        this.selector = selector;
    }

    public void send(ByteBuffer buffer) throws IOException {
        // 先入队再读取
        writeQueue.offer(buffer);

        doWrite();
    }

    public void doWrite() throws IOException {
        while (!writeQueue.isEmpty()) {
            // 查看队头的元素 但是不移除
            ByteBuffer buf = writeQueue.peek();
            int len = channel.write(buf);

            // 当缓冲区写不进去了 监听写事件，等待下次触发
            if (len == 0) {
                System.out.println("当前 Socket 缓冲区写不下去了，开启写监听事件");
                channel.register(selector, SelectionKey.OP_WRITE);
                return;
            }

            // 缓冲区写完，并且buf全部写完 可以移除元素
            if (!buf.hasRemaining()) {
                writeQueue.poll();
            }
        }

        // 找到这个通道注册在监听器的 key; 取消 OP_WRITE 事件监听
        SelectionKey key = channel.keyFor(selector);
        if (key != null) {
            key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
        }
    }
}
